zimmer-media Posted December 26, 2017 Posted December 26, 2017 There is still uncertain, if this function will eventually be installed in the core, here's the guide from the PS forum, for those who can not wait or do not know yet. Step 1 go to your database in prefixfeatureproduct all 3 entrys with primary key from this to this step 2 create "Product.php" at folder /override/classes/ ``` <?php /** * Modification Name: Multiple features for Prestashop * Description: Allows the user to select multiple features for a product * Version: 1.6 * Author: Mellow http://www.prestashop.com/forums/user/344943-mellow * Adaptation to Prestashop 1.5.6: David Bucur http://www.tricksfordevelopers.com * Prestashop 1.6 version: Josef Gullstr�m http://www.prestashop.com/forums/user/597992-jgullstr * License: GPL2 */ class Product extends ProductCore { public static function getFrontFeaturesStatic($id_lang, $id_product) { if (!Feature::isFeatureActive()) return array(); if (!array_key_exists($id_product.'-'.$id_lang, self::$_frontFeaturesCache)) { // Display multi-valued features as comma-separated values in product // data sheet. self::$_frontFeaturesCache[$id_product.'-'.$id_lang] = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT name, GROUP_CONCAT(value SEPARATOR \', \') AS value, pf.id_feature FROM '._DB_PREFIX_.'feature_product pf LEFT JOIN '._DB_PREFIX_.'feature_lang fl ON (fl.id_feature = pf.id_feature AND fl.id_lang = '.(int)$id_lang.') LEFT JOIN '._DB_PREFIX_.'feature_value_lang fvl ON (fvl.id_feature_value = pf.id_feature_value AND fvl.id_lang = '.(int)$id_lang.') LEFT JOIN '._DB_PREFIX_.'feature f ON (f.id_feature = pf.id_feature AND fl.id_lang = '.(int)$id_lang.') '.Shop::addSqlAssociation('feature', 'f').' WHERE pf.id_product = '.(int)$id_product.' GROUP BY pf.id_feature ORDER BY f.position ASC' ); } return self::$_frontFeaturesCache[$id_product.'-'.$id_lang]; } public function addFeaturesToDB($idfeature, $idvalue, $cust = 0) { // Default behavior. if ($cust || !isarray($idvalue)) { return parent::addFeaturesToDB($idfeature, $idvalue, $cust); } // For multi-value features, build array of rows and insert into db. $base = array( 'id_feature' => (int)$id_feature, 'id_product' => (int)$this->id, ); $rows = array(); foreach ($id_value as $value) { if(!empty($value)) { $rows[] = $base + array('id_feature_value' => $value); } } if(!empty($rows)) { Db::getInstance()->insert('feature_product', $rows); } // From parent. SpecificPriceRule::applyAllRules(array((int)$this->id)); if ($id_value) { return ($id_value); } } } ``` Step 3 create "AdminProductsController.php" at folder /override/controllers/admin/ ``` <?php /** * Modification Name: Multiple features for Prestashop * Description: Allows the user to select multiple features for a product * Version: 1.6 * Author: Mellow http://www.prestashop.com/forums/user/344943-mellow * Adaptation to Prestashop 1.5.6: David Bucur http://www.tricksfordevelopers.com * Prestashop 1.6 version: Josef Gullstr�m http://www.prestashop.com/forums/user/597992-jgullstr * License: GPL2 */ class AdminProductsController extends AdminProductsControllerCore { public function initFormFeatures($obj) { if (!$this->default_form_language) $this->getLanguages(); $data = $this->createTemplate($this->tpl_form); $data->assign('default_form_language', $this->default_form_language); if (!Feature::isFeatureActive()) $this->displayWarning($this->l('This feature has been disabled. ').' <a href="index.php?tab=AdminPerformance&token='.Tools::getAdminTokenLite('AdminPerformance').'#featuresDetachables">'.$this->l('Performances').'</a>'); else { if ($obj->id) { if ($this->product_exists_in_shop) { $features = Feature::getFeatures($this->context->language->id, (Shop::isFeatureActive() && Shop::getContext() == Shop::CONTEXT_SHOP)); // Mellow modification. foreach ($features as $k => $tab_features) { $features[$k]['current_item'] = false; $features[$k]['val'] = array(); $features[$k]['custom'] = true; foreach ($obj->getFeatures() as $tab_products) { if ($tab_products['id_feature'] == $tab_features['id_feature']) $features[$k]['current_item'][] = $tab_products['id_feature_value']; } if (!$features[$k]['current_item']) { $features[$k]['current_item'][0] = null; } $features[$k]['featureValues'] = FeatureValue::getFeatureValuesWithLang($this->context->language->id, (int)$tab_features['id_feature']); if (count($features[$k]['featureValues'])) { foreach ($features[$k]['featureValues'] as $value) { if (in_array($value['id_feature_value'], $features[$k]['current_item'])) { $features[$k]['custom'] = false; } } } if ($features[$k]['custom']) { $features[$k]['val'] = FeatureValue::getFeatureValueLang($features[$k]['current_item'][0]); } } // EOF Mellow modification. $data->assign('available_features', $features); $data->assign('product', $obj); $data->assign('link', $this->context->link); $data->assign('languages', $this->_languages); $data->assign('default_form_language', $this->default_form_language); } else $this->displayWarning($this->l('You must save the product in this shop before adding features.')); } else $this->displayWarning($this->l('You must save this product before adding features.')); } $this->tpl_form_vars['custom_form'] = $data->fetch(); } public function processFeatures() { if (!Feature::isFeatureActive()) return; if (Validate::isLoadedObject($product = new Product((int)Tools::getValue('id_product')))) { // delete all objects $product->deleteFeatures(); // add new objects $languages = Language::getLanguages(false); foreach ($_POST as $key => $val) { if (preg_match('/^feature_([0-9]+)_value/i', $key, $match)) { // "&& $val[0] != 0" added by override. if ($val && $val[0] != 0) { $product->addFeaturesToDB($match[1], $val); } else { if ($default_value = $this->checkFeatures($languages, $match[1])) { $id_value = $product->addFeaturesToDB($match[1], 0, 1); foreach ($languages as $language) { if ($cust = Tools::getValue('custom_'.$match[1].'_'.(int)$language['id_lang'])) $product->addFeaturesCustomToDB($id_value, (int)$language['id_lang'], $cust); else $product->addFeaturesCustomToDB($id_value, (int)$language['id_lang'], $default_value); } } } } } } else $this->errors[] = Tools::displayError('A product must be created before adding features.'); } } **Step 4** create "features.tpl" at folder /override/controllers/admin/templates/products/ {* * 2007-2014 PrestaShop * * NOTICE OF LICENSE * * This source file is subject to the Academic Free License (AFL 3.0) * that is bundled with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://opensource.org/licenses/afl-3.0.php * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to [email protected] so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade PrestaShop to newer * versions in the future. If you wish to customize PrestaShop for your * needs please refer to http://www.prestashop.com for more information. * * @author PrestaShop SA [email protected] * @author Josef Gullstr�m http://www.prestashop.com/forums/user/597992-jgullstr * @copyright 2007-2014 PrestaShop SA * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) * International Registered Trademark & Property of PrestaShop SA *} {if isset($product->id)} {l s='Assign features to this product'} {l s='You can specify a value for each relevant feature regarding this product. Empty fields will not be displayed.'} {l s='You can either create a specific value, or select among the existing pre-defined values you\'ve previously added.'} {l s='Feature'} {l s='Pre-defined value'} {l s='or'} {l s='Customized value'} {foreach from=$available_features item=available_feature} {$available_feature.name} {* Changed for multiple-value support *} {if sizeof($available_feature.featureValues)} {foreach from=$available_feature.featureValues item=value} {$value.value|truncate:40} {/foreach} {else} {* /Changed for multiple-value support *} {l s='N/A'} - {l s='Add pre-defined values first'} {/if} {$available_feature.val[1].value|escape:'html':'UTF-8'|default:""} {if $languages|count > 1} {l s='ALL'} {foreach from=$languages item=language} {$language.iso_code} {/foreach} {/if} {foreach from=$languages key=k item=language} {if $languages|count > 1} {/if} {$available_feature.val[$k].value|escape:'html':'UTF-8'|default:""} {if $languages|count > 1} {$language.iso_code} {l s='ALL'} {foreach from=$languages item=language} {$language.iso_code} {/foreach} {/if} {/foreach} {foreachelse} {l s='No features have been defined'} {/foreach} {l s='Add a new feature'} {/if} {/literal} ``` product backoffice product frontoffice if you use blocklayered - your customer have more option when you change the features option in the modul
SLiCK_303 Posted December 27, 2017 Posted December 27, 2017 Step 1 wont let me make a primary outta idfeaturevalue, it gives me this error: #1062 - Duplicate entry '53' for key 'PRIMARY'. (edit) Had to do an export, modify the primary, then an import, but i got it....
zimmer-media Posted December 27, 2017 Author Posted December 27, 2017 I always mark with me all 3 options and then set the primary key for all completely new.
musicmaster Posted December 29, 2017 Posted December 29, 2017 Prestashop has announced multiple features for 1.7.3. I haven't checked out how they will do it but I would prefer to keep compatibility with them. http://build.prestashop.com/news/prestashop-1-7-3-0-beta-1/
wakabayashi Posted December 30, 2017 Posted December 30, 2017 @musicmaster thx for the information. I missed that... This is a must have for tb as well...
Galloper Posted September 11, 2018 Posted September 11, 2018 Hi, guide works great in Prestashop 1.6.1.20. How could feature-values be ordered alphabetically both at front (product datasheet) and backoffice ? thanks!
Galloper Posted September 11, 2018 Posted September 11, 2018 Hi, guide works well in Prestashop 1.6.20.1. How could features-values be ordered alphabeticall both at front (product datasheet) and backoffice (product entry) ? thanks!
wakabayashi Posted September 11, 2018 Posted September 11, 2018 @Galloper What are you talking about? This forum has nothing to do with PS 1.6.20.1
SuperLosiek Posted September 21, 2018 Posted September 21, 2018 Hello. I'm new in Prestashop, got my page done few days ago. I'm looking for the option mentioned in this topic. I have electronic equipment and my goal is to be able to assign multiple values of the same feature to one device (e.g. a device can have 24Vdc or 230Vac power supply version) so the customers can filter it correctly. I do not care about printing this features on product front page. All I want to do is I went through the whole Internet and the only useful information I can see here and here: https://www.prestashop.com/forums/topic/176242-modification-select-multiple-values-for-one-feature/ . I'm working on Prestashop 1.7.2.1 and I'm too scared to update to newest 1.7.4.2 :) Yes, I've heard that multi features option is available since 1.7.3 but for sure it can be also done by modifying core files in 1.7.2 What I've done so far: 1) Step 1 of this instruction. SQL database accepts multiple idfeaturevalue for the same idfeature. I can manually add suitable records to SQL psfeature_products and it is working properly on the website, filtering etc. . Even when I open product editing page, Prestashop loads all the features from the DB. The problem is that when I want to change something in the product, only the last feature is saved (Prestashop overrides SQL database) - I want to change this. 2) From what I understand the whole thing is about modifying processFeatures() funtion in AdminProductsController.php and maybe addFeaturesToDB() function in Product.php. The approach is to gather feature values in processFeatures() function and pass it to addFeaturesToDB() function as an array. Then in addFeaturesToDB() function add to the array idfeature, idproduct and write it to DB. AdminProductsController.php: ``` public function processFeatures($id_product = null) { if (!Feature::isFeatureActive()) { return; } $id_product = (int) $id_product ? $id_product : (int)Tools::getValue('id_product'); if (Validate::isLoadedObject($product = new Product($id_product))) { // delete all objects $product->deleteFeatures(); // add new objects $languages = Language::getLanguages(false); foreach ($_POST as $key => $val) { if (preg_match('/^feature_([0-9]+)_value/i', $key, $match)) { if ($val && $val[0] != 0){ foreach ($val as $feature_val) $product->addFeaturesToDB($match[1], $feature_val); } else { if ($default_value = $this->checkFeatures($languages, $match[1])) { $id_value = $product->addFeaturesToDB($match[1], 0, 1); foreach ($languages as $language) { if ($cust = Tools::getValue('custom_'.$match[1].'_'.(int)$language['id_lang'])) { $product->addFeaturesCustomToDB($id_value, (int)$language['id_lang'], $cust); } else { $product->addFeaturesCustomToDB($id_value, (int)$language['id_lang'], $default_value); } } } } } } } else { $this->errors[] = $this->trans('A product must be created before adding features.', array(), 'Admin.Catalog.Notification'); } } This suppose to get all the features values into array val and pass it to addFeaturesToDB(). I have also tried the way it is shown in this post so without "foreach ($val as $feature_val) $product->addFeaturesToDB($match[1], $feature_val);" but only "$product->addFeaturesToDB($match[1], $val);" in this place. Then we have: addFeaturesToDB(): public function addFeaturesToDB($idfeature, $idvalue, $cust = 0) { // Default behavior. if ($cust) { $row = array('idfeature' => (int)$idfeature, 'custom' => 1); Db::getInstance()->insert('featurevalue', $row); $idvalue = Db::getInstance()->Insert_ID(); } // For multi-value features, build array of rows and insert into db. $base = array( 'id_feature' => (int)$id_feature, 'id_product' => (int)$this->id, ); $rows = array(); foreach ($id_value as $value) { if(!empty($value)) { $rows[] = $base + array('id_feature_value' => $value); } } $row = array('id_feature' => (int)$id_feature, 'id_product' => (int)$this->id, 'id_feature_value' => (int)$id_value); Db::getInstance()->insert('feature_product', $row); SpecificPriceRule::applyAllRules(array((int)$this->id)); if ($id_value) return ($id_value); } ``` I build an array with idfeature and idproduct and add id_value array which is val from processFeatures() function. But it does not work. Can you help me, please? Maybe since Prestashop 1.7.4 is released someone can look up how they are solving this issue? Best regards, Jacek
Traumflug Posted September 21, 2018 Posted September 21, 2018 I’m working on Prestashop 1.7.2.1 Say hello to thirty bees! Here we actually solve misalignments and bugs.
piet Posted September 21, 2018 Posted September 21, 2018 @traumflug said in products with multiple features: Say hello to thirty bees! Here we actually solve misalignments and bugs. Great answer :) It seems ps users are looking for answers on the TB forum
SuperLosiek Posted September 24, 2018 Posted September 24, 2018 Nvm, I found the solution here: https://www.prestashop.com/forums/topic/587538-select-multiple-values-for-one-feature/ works for 1.7.2.1 :)
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now